﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using TorchView.Game;

namespace TorchView.GameContent.Data
{
  public static class AdmSerializer
  {
    public static DataBlock Load(string filename)
    {
      return Load(File.OpenRead(filename));
    }

    public static DataBlock Load(Stream dataStream)
    {
      BinaryReader reader = null;
      try
      {
        reader = new BinaryReader(dataStream);
        uint fileVersion = reader.ReadUInt32();

        Dictionary<int, string> strings = ReadStrings(reader);

        return ReadDataBlock(reader, strings);
      }
      finally
      {
        if (reader != null)
          reader.Close();
      }
    }

    private static DataBlock ReadDataBlock(BinaryReader reader, Dictionary<int, string> nameMap)
    {
      DataBlock block = new DataBlock();

      string name;
      nameMap.TryGetValue(reader.ReadInt32(), out name);
      block.Name = name;

      block.Properties = ReadProperties(reader, nameMap);
      block.SubBlocks = ReadSubBlocks(reader, nameMap);

      return block;
    }

    private static DataProperty ReadProperty(BinaryReader reader, Dictionary<int, string> nameMap)
    {
      string propertyName;
      nameMap.TryGetValue(reader.ReadInt32(), out propertyName);
      PropertyType type = (PropertyType)reader.ReadInt32();
      object value;
      switch (type)
      {
        case PropertyType.INTEGER:
          value = reader.ReadInt32();
          break;
        case PropertyType.FLOAT:
          value = reader.ReadSingle();
          break;
        case PropertyType.DOUBLE:
          value = reader.ReadDouble();
          break;
        case PropertyType.UINTEGER:
          value = reader.ReadUInt32();
          break;
        case PropertyType.TRANSLATE:
        case PropertyType.STRING:
          string valueName;
          nameMap.TryGetValue(reader.ReadInt32(), out valueName);
          value = valueName;
          break;
        case PropertyType.BOOL:
          value = reader.ReadInt32() != 0;
          break;
        case PropertyType.INTEGER64:
          value = reader.ReadInt64();
          break;
        default:
          value = null;
          break;
      }
      return new DataProperty { Name = propertyName, Type = type, Value = value };
    }

    private static Dictionary<int, string> ReadStrings(BinaryReader reader)
    {
      int stringCount = reader.ReadInt32();
      Dictionary<int, string> strings = new Dictionary<int, string>();
      for (int i = 0; i < stringCount; i++)
      {
        int id = reader.ReadInt32();
        string name = SVTHelper.ReadString32(reader);
        strings.Add(id, name);
      }
      return strings;
    }

    private static List<DataProperty> ReadProperties(BinaryReader reader, Dictionary<int, string> nameMap)
    {
      int propertyCount = reader.ReadInt32();
      List<DataProperty> properties = new List<DataProperty>(propertyCount);
      for (int i = 0; i < propertyCount; i++)
        properties.Add(ReadProperty(reader, nameMap));
      return properties;
    }

    private static List<DataBlock> ReadSubBlocks(BinaryReader reader, Dictionary<int, string> nameMap)
    {
      int blockCount = reader.ReadInt32();
      List<DataBlock> subBlocks = new List<DataBlock>(blockCount);
      for (int i = 0; i < blockCount; i++)
        subBlocks.Add(ReadDataBlock(reader, nameMap));
      return subBlocks;
    }
  }
}
